#include "ftpinst.h"

ftpInst::ftpInst(QWidget *parent) : QWidget(parent)
{
    ftp = new QFtp(this);
    connect(ftp, SIGNAL(commandFinished(int, bool)), this, SLOT(ftpCommandFinished(int, bool)) );
    connect(ftp, SIGNAL(listInfo(const QUrlInfo &)), this, SLOT(addToList(const QUrlInfo &)) );

    mainWidget = 0;
    ftpParentItem = 0;
    clickedItem = 0;

    isRefresh = false;

    queryTimer = new QTimer(this);
    connect(queryTimer, SIGNAL(timeout()), this, SLOT( updateTimer()));
}

ftpInst::~ftpInst()
{
    ftp->deleteLater();
}

void ftpInst::setParentTreeWidgetItem( QTreeWidgetItem * parentItem )
{
    ftpParentItem = parentItem;
}

void ftpInst::setClickedTreeWidgetItem( QTreeWidgetItem * clickItem )
{
    clickedItem = clickItem;
}

void ftpInst::setInputParameters( QString& host, QString& login, QString& pass, QString& remDir )
{
    hostname = host;
    username = login;
    password = pass;
    remoteDir = remDir;
}

bool ftpInst::matchHost( const QString& host )
{
    bool ret = false;
    if ( hostname == host )
        ret = true;
    return ret;
}

void ftpInst::proceedFolder()
{
    if ( clickedItem )
    {
        isRefresh = false;
        QString par;
        for( int i = 0; i < getFullUrlPath( clickedItem ).count('/')-2; i++ )
            par.append("/");

        ftp->cd(par);
        ftp->cd( getFullUrlPath( clickedItem ).remove( hostname + "/" ) );
        ftp->list();
        clickedItem->setExpanded( true );
    }
}

void ftpInst::connectFtp()
{
    QUrl url( hostname );
    queryTimer->setInterval( 500 );
    queryTime.start();
    queryTimer->start();

    ftp->connectToHost( url.host(), url.port(21) );

    if ( username.isEmpty() )
        ftp->login(QUrl::fromPercentEncoding(url.userName().toLatin1()), url.password());
    else
        ftp->login( username, password );
}

void ftpInst::addToList( const QUrlInfo &urlInfo )
{
    if ( isRefresh )
    {
        if ( !ftpParentItem )
        {
            bool found = false;
            for ( int i = 0; i < mainWidget->topLevelItemCount(); i++ )
            {
                if ( mainWidget->topLevelItem(i)->text(25) == urlInfo.name() )
                {
                    // mark matched items
                    mainWidget->topLevelItem(i)->setText(27, "+");
                    found = true;

                    if ( mainWidget->topLevelItem(i)->text(27) != "+" &&
                         mainWidget->topLevelItem(i)->text(29) != urlInfo.lastModified().toString( Qt::ISODate ) )
                    {
                        modified++;
                        drawTreeItem( mainWidget->topLevelItem(i), false, urlInfo );

                        for ( int col = 0; col < mainWidget->columnCount(); col++ )
                        {
                            mainWidget->topLevelItem(i)->setForeground( col, QBrush( QColor(0, 0, 255) ) );
                            QFont font = mainWidget->topLevelItem(i)->font(0);
                            font.setBold( true );
                            mainWidget->topLevelItem(i)->setFont( col, font );
                        }
                        break;
                    }
                }
            }
            if ( !found )
            {
                QTreeWidgetItem *item = new QTreeWidgetItem;
                if ( urlInfo.isDir() )
                    item->setExpanded( true );
                mainWidget->addTopLevelItem( item );

                drawTreeItem( item, urlInfo.isDir(), urlInfo );
                ftpItemsList[getFullUrlPath( item )] = urlInfo;

                item->setText( 27, "a" );
                for ( int i = 0; i < mainWidget->columnCount(); i++ )
                {
                    item->setForeground( i, QBrush( QColor(0, 130, 0) ) );
                    QFont font = item->font(0);
                    font.setBold( true );
                    item->setFont( i, font );
                }
                added++;
            }
        }
        else // check inner branch
        {
            bool found = false;
            for ( int i = 0; i < ftpParentItem->childCount(); i++ )
            {
                if ( ftpParentItem->child(i)->text(25) == urlInfo.name() )
                {
                    found = true;
                    if ( ftpParentItem->child(i)->text(27) != "+" &&
                         ftpParentItem->child(i)->text(29) != urlInfo.lastModified().toString( Qt::ISODate ) )
                    {
                        modified++;
                        drawTreeItem( ftpParentItem->child(i), false, urlInfo );

                        for ( int col = 0; col < mainWidget->columnCount(); col++ )
                        {
                            ftpParentItem->child(i)->setForeground( col, QBrush( QColor(0, 0, 255) ) );
                            QFont font = ftpParentItem->child(i)->font(0);
                            font.setBold( true );
                            ftpParentItem->child(i)->setFont( col, font );
                        }
                        break;
                    }
                    ftpParentItem->child(i)->setText(27, "+");
                }
            }
            if ( !found )
            {
                QTreeWidgetItem *item = new QTreeWidgetItem;
                if ( urlInfo.isDir() )
                    item->setExpanded( true );
                ftpParentItem->addChild(item);

                drawTreeItem( item, urlInfo.isDir(), urlInfo );
                ftpItemsList[getFullUrlPath( item )] = urlInfo;

                item->setText( 27, "a" );
                for ( int i = 0; i < mainWidget->columnCount(); i++ )
                {
                    item->setForeground( i, QBrush( QColor(0, 130, 0) ) );
                    QFont font = item->font(0);
                    font.setBold( true );
                    item->setFont( i, font );
                }
                added++;
            }
        }
    }
    else
    {
        QTreeWidgetItem *item = new QTreeWidgetItem;
        if ( urlInfo.isDir() )
            item->setExpanded( true );

        if ( !clickedItem )
        {
            if ( ftpParentItem )
                ftpParentItem->addChild(item);
            else
                mainWidget->addTopLevelItem( item );
        }
        else
            clickedItem->addChild(item);

        drawTreeItem( item, urlInfo.isDir(), urlInfo );
        ftpItemsList[getFullUrlPath( item )] = urlInfo;
    }
}

void ftpInst::ftpCommandFinished(int commID, bool error)
{
    queryTimer->stop();
    if ( ftp->currentCommand() == QFtp::Cd && error )
        emit commandError( QString("Cd"), ftp->errorString() );

    if ( ftp->currentCommand() == QFtp::ConnectToHost && error )
        emit commandError( QString("ConnectToHost"), ftp->errorString() );

    if (ftp->currentCommand() == QFtp::Login)
    {
        if (error)
        {
            if ( ftp->error() == QFtp::UnknownError )
            {
                loginDialog lDial(this);
                if ( lDial.exec() )
                    ftp->login( lDial.getLogin(), lDial.getPassword() );
                else
                emit commandError( QString("LoginCancel"), ftp->errorString() );
            }
            else
                emit commandError( QString("Login"), ftp->errorString() );
        }
        else
        {
            if ( remoteDir.isEmpty() )
                ftp->list();
            else
            {
                ftp->cd( remoteDir );
                ftp->list();
            }
        }
    }

    if (ftp->currentCommand() == QFtp::List)
    {
        if (error)
            emit commandError( QString("List"), ftp->errorString() );
        else if ( !isRefresh )
            emit listDone();
        else
        {
            // check deleted
            if ( ftpParentItem )
            {
                for ( int i = 0; i < ftpParentItem->childCount(); i++ )
                {
                    if ( ftpParentItem->child(i)->text(27).isEmpty() &&
                         ftpParentItem->child(i)->text(30) == "ftp" )
                    {
                        ftpItemsList.remove( ftpParentItem->child(i)->text(26) );
                        ftpParentItem->takeChild( i );
                        deleted++;
                    }
                }
            }
            else
            {
                for ( int i = 0; i < mainWidget->topLevelItemCount(); i++ )
                {
                    if ( mainWidget->topLevelItem(i)->text(27).isEmpty()
                         && mainWidget->topLevelItem(i)->text(30) == "ftp" )
                    {
                        ftpItemsList.remove( mainWidget->topLevelItem(i)->text(26) );
                        mainWidget->takeTopLevelItem (i);
                        deleted++;
                    }
                }
            }
            emit refreshDone( added, modified, deleted );
        }
    }
}

void ftpInst::drawTreeItem( QTreeWidgetItem * item, bool isFolder, const QUrlInfo &urlInfo )
{
    int col = -1;
    QString dispFileName = urlInfo.name().left( urlInfo.name().lastIndexOf('.') );
    if ( mySettings->displayFileExtension() )
    {
        if ( mySettings->attachToFilename() )
            dispFileName = urlInfo.name();
        else if ( !isFolder )
        {
            col = customColumnNumber( "File ext" );
            if ( col != -1 )
            {
                int extLen = urlInfo.name().length() - urlInfo.name().lastIndexOf('.') - 1;
                item->setData( col, Qt::DisplayRole,
                               urlInfo.name().right( extLen ));
            }
        }
    }
    item->setText( 0, dispFileName );
    //8.3 name format
    if ( !isFolder )
    {
        item->setData( 20, Qt::DisplayRole,
                       urlInfo.name().left( urlInfo.name().lastIndexOf('.') ).left(8) + "." + urlInfo.name().right( urlInfo.name().lastIndexOf('.')).left(3) );
    }
    else
        item->setData( 20, Qt::DisplayRole, dispFileName );

    QPixmap pixmap( isFolder ? ":/images/folder.png" : ":/images/file.png");
    item->setIcon ( 0, pixmap );

    col = customColumnNumber( "Type" );
    if ( !isFolder )
    {
        if ( col != -1 )
            item->setData( col, Qt::DisplayRole, "file" );
        item->setData( 22, Qt::DisplayRole, "file" );
    }
    else
    {
        if ( col != -1 )
            item->setData( col, Qt::DisplayRole, "folder" );
        item->setData( 22, Qt::DisplayRole, "folder" );
    }

    col = customColumnNumber( "Full path" );
    if ( col != -1 )
        item->setData( col, Qt::DisplayRole, getFullUrlPath( item ) );

    if ( !isFolder )
    {
        col = customColumnNumber( "Size" );
        if ( col != -1 )
            item->setData( col, Qt::DisplayRole, getConvertedSize( urlInfo.size() ) );
    }

    col = customColumnNumber( "Creation date" );
    if ( col != -1 )
        item->setData( col, Qt::DisplayRole, "" );

    col = customColumnNumber( "Modification date" );
    if ( col != -1 )
        item->setData( col, Qt::DisplayRole, urlInfo.lastModified().toString( mySettings->getDateFormat() + " " + mySettings->getTimeFormat() ));

    col = customColumnNumber( "Last access date" );
    if ( col != -1 )
        item->setData( col, Qt::DisplayRole, urlInfo.lastRead().toString( mySettings->getDateFormat() + " " + mySettings->getTimeFormat() ));

    col = customColumnNumber( "File attr" );
    if ( col != -1 )
        item->setData( col, Qt::DisplayRole, getUrlAttr( urlInfo ) );

    col = customColumnNumber( "Owner" );
    if ( col != -1 )
        item->setData( col, Qt::DisplayRole, urlInfo.owner() );

    item->setData( 23, Qt::DisplayRole, QString::number(urlInfo.size()) );
    item->setData( 25, Qt::DisplayRole, urlInfo.name() );
    item->setData( 26, Qt::DisplayRole, getFullUrlPath( item ) );
    item->setData( 28, Qt::DisplayRole, getUrlAttr( urlInfo ) );
    item->setData( 29, Qt::DisplayRole, urlInfo.lastModified().toString( Qt::ISODate ) );
    item->setText( 30, "ftp" );
}

int ftpInst::customColumnNumber( const QString& name )
{
    int resCol = -1;
    for (int i = 0; i < mainWidget->columnCount(); i++ )
    {
        if ( mainWidget->headerItem()->text(i).left( name.length() ) == name )
        {
            resCol = i;
            break;
        }
    }
    return resCol;
}

QString ftpInst::getConvertedSize( qint64 _size )
{
    if ( mySettings->displayFileSizeType() != 5 )
    {
        double ret = _size;
        for ( int it = 1; it < mySettings->displayFileSizeType(); it++ )
            ret = ret / 1024;

        QString suff;
        switch ( mySettings->displayFileSizeType() )
        {
        case 1:
            {
                suff = " bytes";
                break;
            }
        case 2:
            {
                suff = " kb";
                break;
            }
        case 3:
            {
                suff = " Mb";
                break;
            }
        case 4:
            {
                suff = " Gb";
                break;
            }
        }

        QString retStr = QString::number( ret, 'f', 2 );
        retStr.replace( retStr.mid( retStr.length()-3, 1 ), mySettings->getFractionDel() );

        int _count = (retStr.length()-3)/3+1;
        if ( _count == (retStr.length()-3)/3 )
            _count--;
        for (int i = 1; i < _count; i++)
            retStr.insert( (retStr.length()-3)-(3*i)-(i-1), mySettings->getGroupSeparator() );
        retStr += suff;
        retStr = retStr.simplified();
        return retStr;
    }
    else
    {
        double bytesCount = _size;

        int degree = -1;
        QString degreeStr = " bytes";
        while ( bytesCount >= 1 )
        {
            bytesCount = bytesCount / 1024.0;
            degree++;
        }

        bytesCount *= 1024.0;
        switch ( degree )
        {
        case 1:
            {
                degreeStr = " kb";
                break;
            }
        case 2:
            {
                degreeStr = " Mb";
                break;
            }
        case 3:
            {
                degreeStr = " Gb";
                break;
            }
        }
        QString retStr = QString::number( bytesCount, 'f', 2 );
        retStr.replace( retStr.mid( retStr.length()-3, 1 ), mySettings->getFractionDel() );

        int _count = (retStr.length()-3)/3+1;
        if ( _count == (retStr.length()-3)/3 )
            _count--;
        for (int i = 1; i < _count; i++)
            retStr.insert( (retStr.length()-3)-(3*i)-(i-1), mySettings->getGroupSeparator() );
        retStr += degreeStr;
        retStr = retStr.simplified();
        return retStr;
    }

    return QString::null;
}

QString ftpInst::getUrlAttr( const QUrlInfo &urlInfo )
{
    QString retStr;
    if ( urlInfo.isSymLink() )
        retStr += "System";
    if ( !urlInfo.isWritable() )
    {
        if ( !retStr.isEmpty() )
            retStr += "; ";
        retStr += "Read only";
    }
    return retStr;
}

QString ftpInst::getFullUrlPath( QTreeWidgetItem *item )
{
    QString retStr = hostname;
    QString appendix = "/" + item->text(0);

    QTreeWidgetItem *itemParent = item->parent();
    while ( itemParent )
    {
        if ( itemParent->parent() )
            appendix.prepend( "/" + itemParent->text(0) );
        itemParent = itemParent->parent();
    }

    return retStr + appendix;
}

void ftpInst::refresh()
{
    if ( ftp )
    {
        deleted = 0;
        modified = 0;
        added = 0;

        isRefresh = true;

        ftp->cd("/////////////////////");
        if ( !remoteDir.isEmpty() )
            ftp->cd(remoteDir);
        ftp->list();
    }
}

void ftpInst::settingsChanged()
{
    QTreeWidgetItemIterator iter1( mainWidget );
    while (*iter1)
    {
        if ( (*iter1)->text(30) == "ftp" && mainWidget->indexOfTopLevelItem(*iter1) == -1 )
        {
            QUrlInfo urlInfo( ftpItemsList[(*iter1)->text(26)] );

            for (int i = 0; i < 31; i++)
                (*iter1)->setText( i, QString::null );
            drawTreeItem( *iter1, urlInfo.isDir(), urlInfo );
        }
        ++iter1;
    }
}

void ftpInst::updateTimer()
{
    if ( queryTime.elapsed() > 10*1000 ) // 10sec timeout!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    {
        queryTimer->stop();
        emit commandError( QString("FTP connect"), "Remote server doesn't respond" );
    }
}
